package metar;

/**
 * Wolkeninformationen auswerten
 * @author Michel Metzger, Java-Kurs 2013
 * @version 1.0.0
 *
 */
public class CloudsMetar implements MetarParamInterface {

	/**
	 * Informationen zur Bewölkung: CAVOK, NSC, FEW, SCT, BKN, OVC => No cloud/Sky clear, Nil Significant Cloud, Few, Scattered, Broken, Overcast
	 */
	private String	clouds;
	
	/**
	 * Wolkenuntergrenze in Fuß
	 */
	private int		cloudCeiling;
	
	/**
	 * Wolkenart: TCU, CB => Towering Cumulus, Cumulonimbus
	 */
	private String	cloudType;

	/**
	 * Originalwert aus der Metar-info
	 */
	private String origParam;

	/**
	 * Konstruktor
	 */
	public CloudsMetar() {
		clouds = "";
		cloudCeiling = 0;
		cloudType = "";
	}

	/**
	 * Liefert die Infos zur Bewölkung
	 * @return
	 */
	public String getClouds() {
		return clouds;
	}

	/**
	 * Liefert die Wolkenuntergrenze in Fuß
	 * @return
	 */
	public int getCloudCeiling() {
		return cloudCeiling;
	}

	/**
	 * Liefert die Art der Bewölkung
	 * @return
	 */
	public String getCloudType() {
		return cloudType;
	}

	/**
	 * Liefert den original Parameter aus dem MetarInfo
	 * @return
	 */
	public String getOrigParam() {
		return origParam;
	}

	/**
	 * Liefert true, wenn der angegebene Parameter eine Wolkeninfo enthält
	 * @param val
	 * @return
	 */
	public static boolean isValid(String val) {
		if (val == null) {
			return false;
		}

		val = val.toUpperCase();
		if (val.toUpperCase().compareTo("CAVOK") == 0) {
			return true;
		} else if (val.matches("\\D{3}\\d{3}\\D{0,3}")) {
			return true;
		} else if (val.length() == 3) {
			/**
			 * Bei einigen Flughäfen kommt nur die Abkürzung ohne weitere Infos
			 */
			final String[] cloudTypes = { "SKC", "CLR", "NSC", "FEW", "SCT", "BKN", "OVC" };
			for (int i = 0; i < cloudTypes.length; ++i) {
				if (val.compareTo(cloudTypes[i]) == 0) {
					return true;
				}
			}
		}
		
		return false;
	}

	/**
	 * Wolkendaten aus dem Parameter laden
	 * @return
	 * @throws MetarParseException
	 */
	@Override
	public CloudsMetar parseParam(String val) throws MetarParseException {
		if (!isValid(val)) {
			throw new MetarParseException("Exception while parsing clouds!");
		}
		
		/**
		 * Sample:
		 * FEW040TCU = Bewölkung: Stärke (FEW = 1 bis 2 Achtel), Höhe der Wolkenuntergrenze (4.000 Fuß über Grund) und Art der Bew�lkung (TCU = towering cumulus)
		 */

		try {
			origParam = val;
			
			if (val.toUpperCase().compareTo("CAVOK") == 0) {
				clouds = "No cloud/Sky clear";
			} else {
				/**
				 * SKC 	'No cloud/Sky clear' used worldwide but in North America is used to indicate a human generated report[11][12]
				 * CLR 	'No clouds below 12,000 ft (3,700 m) (US) or 10,000 ft (3,000 m) (Canada)' used mainly within North America and indicates a station that is at least partly automated[11][12]
				 * NSC 	'No (nil) significant cloud' (i.e. none below 5,000 ft (1,500 m) and no TCU or CB) not used in North America
				 * FEW 	'Few' = 1-2 oktas
				 * SCT 	'Scattered' = 3-4 oktas
				 * BKN 	'Broken' = 5-7 oktas
				 * OVC 	'Overcast' = 8 oktas (ie full cloud coverage)
				 * VV 	'Vertical Visibility' until full cloud coverage.				
				 */
				clouds = val.substring(0, 3);
				switch(clouds) {
				case "SKC" : clouds = "No cloud/Sky clear"; 		break;
				case "CLR" : clouds = "No clouds below 3,700 m"; 	break;
				case "NSC" : clouds = "No significant cloud"; 		break;
				case "FEW" : clouds = "Few clouds"; 				break;
				case "SCT" : clouds = "Scattered clouds"; 			break;
				case "BKN" : clouds = "Broken clouds"; 				break;
				case "OVC" : clouds = "Overcast clouds"; 			break;
				}
				
				if (val.length() >= 6) {
					cloudCeiling = Integer.valueOf(val.substring(3,6)) * 100;
				}
				
				if (val.length() >= 8) {
					/**
					 * TCU 	Towering Cumulus
					 * CB 	Cumulonimbus				
					 */
					cloudType = val.substring(6);
					switch(cloudType) {
					case "TCU" : cloudType = "Towering Cumulus"; 	break;
					case "CB" :  cloudType = "Cumulonimbus"; 		break;
					}
				}
			}
		} catch (NumberFormatException e) {
			if (MetarInfo.isDebugMode()) {
				e.printStackTrace();
			}
			throw new MetarParseException("Exception while parsing clouds!", e);
		}
		
		if (MetarInfo.isDebugMode()) {
			System.out.println("*** Clouds.clouds=" + clouds);
			System.out.println("*** Clouds.cloudCeiling=" + cloudCeiling + " ft");
			System.out.println("*** Clouds.cloudType=" + cloudType);
		}
		
		return this;
	}

}
